package com.shycloud.mido.homework.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.shycloud.mido.common.core.constant.CommonConstants;
import com.shycloud.mido.common.core.util.R;
import com.shycloud.mido.homework.api.dto.WeekDataDto;
import com.shycloud.mido.homework.api.entity.WeekDataMember;
import com.shycloud.mido.homework.api.entity.WeekMain;
import com.shycloud.mido.homework.api.vo.HomeworkDaysPlayingModeVO;
import com.shycloud.mido.homework.api.vo.WeekDataDayVO;
import com.shycloud.mido.homework.api.vo.WeekDataHomeworkVO;
import com.shycloud.mido.homework.mapper.WeekDataMemberMapper;
import com.shycloud.mido.homework.service.WeekDataMemberService;
import com.shycloud.mido.homework.service.WeekMainService;
import com.shycloud.mido.member.api.feign.RemoteMemberService;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDate;
import java.time.LocalDateTime;

/**
 * <p>
 * 周报数据周维度表 前端控制器
 * </p>
 *
 * @author baiqiang
 * @since 2021-06-15
 */
@RestController
@RequestMapping("/homework/week-data-member")
@AllArgsConstructor
public class WeekDataMemberController {

	/** 周报用户数据 service */
	private final WeekDataMemberService weekDataMemberService;
	/** 周报主表 service */
	private final WeekMainService weekMainService;
	/** 周报用户数据 mapper */
	private final WeekDataMemberMapper weekDataMemberMapper;

	private final RemoteMemberService memberService;
	/** 查询的类型：上周数据 */
	private static final String WEEK_TYPE_PRE = "-1";
	/** 查询的类型：本周数据 */
	private static final String WEEK_TYPE_NOW = "0";
	/** 查询的类型：同年龄数据 */
	private static final String WEEK_TYPE_AGE = "1";
	/** 查询的类型：同学龄数据 */
	private static final String WEEK_TYPE_PLAY_AGE = "2";
	/** 查询的类型：同目标数据 */
	private static final String WEEK_TYPE_TARGET = "3";

	@GetMapping("getWeekAllTime")
	@ApiOperation("获取用户周练琴总时长以及排名百分比")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "weekId", value = "周报ID", paramType = "query", dataType = "String"),
			@ApiImplicitParam(name = "memberId", value = "用户ID", paramType = "query", dataType = "String"),
			@ApiImplicitParam(name = "studentId", value = "学生ID", paramType = "query", dataType = "String")
	})
	public R getWeekAllTime(String memberId, String studentId, String weekId) {
		return new R<>(weekDataMemberService.getWeekAllTime(memberId, studentId, weekId));
	}


	@GetMapping("getWeekData")
	@ApiOperation("获取用户弹琴数据(周维度)")
	@Cacheable(value = "week_getWeekData", key = "'week_getWeekData_'+#weekId+'_'+#type+'_'+#memberId")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "weekId", value = "周报ID", paramType = "query", dataType = "String"),
			@ApiImplicitParam(name = "type", value = "类型(-1-上周，0-本周，1-年龄 2-学龄 3-目标)", paramType = "query", dataType = "String")
	})
	public R<WeekDataHomeworkVO> getWeekData(String weekId, String type, String memberId) {

		WeekDataHomeworkVO weekDataHomeworkVO = new WeekDataHomeworkVO();

		//获取周报用户信息
		WeekDataMember weekDataMember = weekDataMemberService.getOne(new QueryWrapper<WeekDataMember>()
				.eq("week_id", weekId)
				.eq("member_id", memberId));

		//本周练琴数据
		WeekDataMember weekDataMemberThisWeek = weekDataMemberService.getOne(new QueryWrapper<WeekDataMember>()
				.eq("member_id", memberId)
				.eq("week_id", weekId));

		//上周练琴数据
		WeekDataMember weekDataMemberPreWeek = weekDataMemberService.getOne(new QueryWrapper<WeekDataMember>()
				.eq("member_id", memberId)
				.eq("week_id", weekDataMember.getPreWeekId()));
		if (weekDataMemberPreWeek == null) {
			weekDataMemberPreWeek = new WeekDataMember();
		}
		//周作业完成总数
		weekDataHomeworkVO.setHomeworkDoneCount(weekDataMemberThisWeek.getHomeworkDoneCount());
		// 作业数排名
		weekDataHomeworkVO.setHomeworkDoneCountRank(memberService.getHomeworkDoneCountRank(weekId, memberId));
		// 周作业完成总人数
		weekDataHomeworkVO.setHomeworkAllCount(weekDataMemberMapper
				.selectCount(new QueryWrapper<WeekDataMember>().eq("week_id", weekId)));
		// 周作业完成率
		weekDataHomeworkVO.setHomeworkDoneRate(weekDataMemberThisWeek.getHomeworkRate());
		// 上周作业完成率
		weekDataHomeworkVO.setPreHomeworkDoneRate(weekDataMemberPreWeek.getHomeworkRate());
		// 本周作业完成情况
		weekDataHomeworkVO.setThisWeekHomeworkDetail(weekDataMemberThisWeek);

		// 比较的作业完成情况（上周/年龄/学龄/目标）
		if (WEEK_TYPE_PRE.equals(type)) {
			weekDataHomeworkVO.setCompareWeekHomeworkDetail(weekDataMemberPreWeek);
		}
		//筛选年龄数据
		if (WEEK_TYPE_AGE.equals(type)) {
			weekDataHomeworkVO
					.setCompareWeekHomeworkDetail(weekDataMemberMapper.getPlayData(weekId, weekDataMember.getAge(), null, null));
		}
		//筛选学龄数据
		if (WEEK_TYPE_PLAY_AGE.equals(type)) {
			weekDataHomeworkVO
					.setCompareWeekHomeworkDetail(weekDataMemberMapper.getPlayData(weekId, null, weekDataMember.getPlayYears(), null));
		}
		//筛选目标数据
		if (WEEK_TYPE_TARGET.equals(type)) {
			weekDataHomeworkVO
					.setCompareWeekHomeworkDetail(
							weekDataMemberMapper.getPlayData(weekId, null, null, weekDataMember.getPlayTarget()));
		}

		return new R<>(weekDataHomeworkVO);
	}

	/**
	 * 快乐斑马练琴周报(日均时长) [本周中每天的练琴时长及时间分布]
	 *
	 * @param weekId    周报 ID
	 * @param type      类型
	 * @param studentId 学生 ID
	 * @return com.shycloud.mido.common.core.util.R
	 * @author nianhua.jiang
	 * @date 2021/7/30 9:50
	 */
	@GetMapping("getDayData")
	@ApiOperation("获取用户弹琴数据(日维度)(日均时长)")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "weekId", value = "周报ID", paramType = "query", dataType = "String"),
			@ApiImplicitParam(name = "type", value = "类型(-1-上周，0-本周，1-年龄 2-学龄 3-目标)", paramType = "query", dataType = "String"),
			@ApiImplicitParam(name = "studentId", value = "学生ID", paramType = "query", dataType = "String"),
			@ApiImplicitParam(name = "memberId", value = "用户ID", paramType = "query", dataType = "String")
	})
	@Cacheable(value = "week_getDayData", key = "'week_getDayData_'+#weekId+'_'+#type+'_'+#studentId")
	public R getDayData(String weekId, String type, String studentId) {

		List<WeekDataMember> weekDataMembers = weekDataMemberService.list(new QueryWrapper<WeekDataMember>()
				.eq("week_id", weekId)
				.eq("student_id", studentId));

		if (weekDataMembers.size() == 0) {
			return new R<>(CommonConstants.FAIL, "暂时还没有您的周报，若您刚刚订阅，请您下周再来呦", false);
		}

		WeekDataMember weekDataMember = weekDataMembers.get(0);

		//主表
		WeekMain weekMain = weekMainService.getById(weekId);

		if (weekMain == null) {
			return new R(CommonConstants.FAIL, "根据 weekId 查询不到周报信息，请确认", false);
		}
		//构建返回体
		WeekDataDayVO weekDataDayVO = new WeekDataDayVO();
		//计算时间段
		LocalDate startWeekDate = weekMain.getStartWeekDate();
		LocalDate endWeekDate = weekMain.getEndWeekDate();
		LocalDateTime startTime = startWeekDate.atTime(0, 0, 0, 0);
		LocalDateTime endTime = endWeekDate.atTime(23, 59, 59);

		List<WeekDataDto> playDataDay = weekDataMemberMapper.getPlayDataDay(weekId, studentId, startTime, endTime, null, null, null);

		Double playTimes = playDataDay.stream().collect(Collectors.summingDouble(WeekDataDto::getPlayTime));
		//本周平均练琴时长
		weekDataDayVO.setAverageTime(new BigDecimal(playTimes).divide(new BigDecimal(7), 1, RoundingMode.HALF_UP).doubleValue());
		//每天练琴时长
		weekDataDayVO.setThisWeekDayTimes(playDataDay);

		//上周数据
		List<WeekDataDto> playDataDayPre = new ArrayList<>();
		if (weekMain.getPreWeekId() != null && !StringUtils.equals(weekMain.getPreWeekId(), "0")) {
			WeekMain weekMainPre = weekMainService.getById(weekMain.getPreWeekId());
			//计算时间段
			LocalDate startWeekDatePre = weekMainPre.getStartWeekDate();
			LocalDate endWeekDatePre = weekMainPre.getEndWeekDate();
			LocalDateTime startTimePre = startWeekDatePre.atTime(0, 0, 0, 0);
			LocalDateTime endTimePre = endWeekDatePre.atTime(23, 59, 59);
			playDataDayPre = weekDataMemberMapper.getPlayDataDay(weekId, studentId, startTimePre, endTimePre, null, null, null);
			Double playTimesPre = playDataDayPre.stream().collect(Collectors.summingDouble(WeekDataDto::getPlayTime));
			//比上周多的分钟数
			weekDataDayVO.setOverPreTime(new BigDecimal(playTimes - playTimesPre).setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue());
			weekDataDayVO.setCompareAverageTime(playTimesPre / 7);
		} else {
			//比上周多的分钟数
			weekDataDayVO.setOverPreTime(new BigDecimal(playTimes).setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue());
			weekDataDayVO.setCompareAverageTime(0d);
		}

		if (StringUtils.equals(type, WEEK_TYPE_PRE)) {
			weekDataDayVO.setCompareWeekDayTimes(playDataDayPre);
		}
		// 同年龄段平均时长
		if (StringUtils.equals(type, WEEK_TYPE_AGE)) {
			List<WeekDataDto> playDataDayAge = weekDataMemberMapper
					.getPlayDataDay(weekId, null, startTime, endTime, weekDataMember.getAge(), null, null);
			//获取【同龄人】人数
			List<WeekDataMember> res = weekDataMemberMapper.selectList(new QueryWrapper<WeekDataMember>()
					.eq("age", weekDataMember.getAge())
					.groupBy("student_id"));
			int count = res.size();
			Double totalTime = 0d;
			for (WeekDataDto weekDataDto : playDataDayAge) {
				totalTime += weekDataDto.getPlayTime();
				weekDataDto.setPlayTime(
						new BigDecimal(weekDataDto.getPlayTime() / count).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
			}

			//获取总分钟数
			weekDataDayVO.setCompareWeekDayTimes(playDataDayAge);
			weekDataDayVO.setAge(weekDataMember.getAge());
			weekDataDayVO.setCompareAverageTime(totalTime / count / 7);
		}
		// 同学龄段平均时长
		if (StringUtils.equals(type, WEEK_TYPE_PLAY_AGE)) {
			List<WeekDataDto> playDataDayPlayAge = weekDataMemberMapper
					.getPlayDataDay(weekId, null, startTime, endTime, null, weekDataMember.getPlayYears(), null);
			//获取【同学龄】人数

			int count = weekDataMemberMapper.selectList(new QueryWrapper<WeekDataMember>()
					.eq("play_years", weekDataMember.getPlayYears())
					.groupBy("student_id")).size();

			Double totalTime = 0d;
			for (WeekDataDto weekDataDto : playDataDayPlayAge) {
				totalTime += weekDataDto.getPlayTime();
				weekDataDto.setPlayTime(
						new BigDecimal(weekDataDto.getPlayTime() / count).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
			}
			weekDataDayVO.setCompareWeekDayTimes(playDataDayPlayAge);
			weekDataDayVO.setPlayYears(weekDataMember.getPlayYears());
			weekDataDayVO.setCompareAverageTime(totalTime / count / 7);
		}
		// 同目标段平均时长
		if (StringUtils.equals(type, WEEK_TYPE_TARGET)) {

			List<WeekDataDto> playDataDayTarget = weekDataMemberMapper
					.getPlayDataDay(weekId, null, startTime, endTime, null, null, weekDataMember.getPlayTarget());

			//获取【同目标】人数
			int count = weekDataMemberMapper.selectList(new QueryWrapper<WeekDataMember>()
					.eq("play_target", weekDataMember.getPlayTarget())
					.groupBy("student_id")).size();
			Double totalTime = 0d;
			for (WeekDataDto weekDataDto : playDataDayTarget) {
				totalTime += weekDataDto.getPlayTime();
				weekDataDto.setPlayTime(
						new BigDecimal(weekDataDto.getPlayTime() / count).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
			}
			weekDataDayVO.setCompareWeekDayTimes(playDataDayTarget);
			weekDataDayVO.setPlayTarget(weekDataMember.getPlayTarget());
			weekDataDayVO.setCompareAverageTime(totalTime / count / 7);
		}

		return new R(weekDataDayVO);
	}

	@GetMapping("getHomeworkDaysPlayingMode")
	@Cacheable(value = "week_getHomeworkDaysPlayingMode", key = "'week_getHomeworkDaysPlayingMode_'+#studentId+'_'+#weekId")
	public R<HomeworkDaysPlayingModeVO> getHomeworkDaysPlayingMode(String studentId, String weekId) {

		//主表
		WeekMain weekMain = weekMainService.getById(weekId);
		if (weekMain == null) {
			return new R(CommonConstants.FAIL, "根据 weekId 查询不到周报信息，请确认", false);
		}

		//计算时间段
		LocalDate startWeekDate = weekMain.getStartWeekDate();
		LocalDate endWeekDate = weekMain.getEndWeekDate();
		LocalDateTime startTime = startWeekDate.atTime(0, 0, 0, 0);
		LocalDateTime endTime = endWeekDate.atTime(23, 59, 59);

		List<HomeworkDaysPlayingModeVO> HomeworkDaysPlayingModes = weekDataMemberMapper
				.getHomeworkDaysPlayingMode(studentId, startTime, endTime);
		/*
		  "playingMode2": [{
								"week": "0",
								"hour": null,
								"playingMode": "2",
								"playTimes": 0,
								"dateTime": "2021-08-29 00:00:00"
							  }, ......(省略)],
		   "playingMode1": [{
								"week": "0",
								"hour": null,
								"playingMode": "1",
								"playTimes": 0,
								"dateTime": "2021-08-29 00:00:00"
					       },......(省略)]

		*/
		Map<String, List<HomeworkDaysPlayingModeVO>> resMap = new HashMap<>(2);

		List<HomeworkDaysPlayingModeVO> playingMode1 = new ArrayList<>(7);
		List<HomeworkDaysPlayingModeVO> playingMode2 = new ArrayList<>(7);

		for (int i = 0; i < 7; i++) {

			HomeworkDaysPlayingModeVO homeworkDaysPlayingMode1 = new HomeworkDaysPlayingModeVO();
			HomeworkDaysPlayingModeVO homeworkDaysPlayingMode2 = new HomeworkDaysPlayingModeVO();
			homeworkDaysPlayingMode1.setPlayingMode("1");
			homeworkDaysPlayingMode2.setPlayingMode("2");
			homeworkDaysPlayingMode1.setWeek(String.valueOf(i));
			homeworkDaysPlayingMode2.setWeek(String.valueOf(i));
			homeworkDaysPlayingMode1.setPlayTimes(0d);
			homeworkDaysPlayingMode2.setPlayTimes(0d);
			homeworkDaysPlayingMode1.setDateTime(startTime.plusDays(i));
			homeworkDaysPlayingMode2.setDateTime(startTime.plusDays(i));

			playingMode1.add(homeworkDaysPlayingMode1);
			playingMode2.add(homeworkDaysPlayingMode2);

			for (HomeworkDaysPlayingModeVO homeworkDaysPlayingMode : HomeworkDaysPlayingModes) {

				if (StringUtils.isNotBlank(homeworkDaysPlayingMode.getWeek())
						&& i == Integer.parseInt(homeworkDaysPlayingMode.getWeek())) {
					if ("1".equals(homeworkDaysPlayingMode.getPlayingMode())) {
						playingMode1.remove(i);
						playingMode1.add(homeworkDaysPlayingMode);
						continue;
					}
					if ("2".equals(homeworkDaysPlayingMode.getPlayingMode())) {
						playingMode2.remove(i);
						playingMode2.add(homeworkDaysPlayingMode);
					}
				}

			}

		}
		resMap.put("playingMode1", playingMode1);
		resMap.put("playingMode2", playingMode2);
		return new R(resMap);
	}

	@GetMapping("getHomeworkDaysPlayingModeHour")
	@Cacheable(value = "week_getHomeworkDaysPlayingModeHour", key = "'week_getHomeworkDaysPlayingModeHour_'+#studentId+'_'+#weekId+'_'+#dateTime")
	public R<HomeworkDaysPlayingModeVO> getHomeworkDaysPlayingModeHour(String studentId, String weekId, String dateTime) {

		List<Map<String, HomeworkDaysPlayingModeVO>> resList = new ArrayList<>();
		//主表
		WeekMain weekMain = weekMainService.getById(weekId);
		if (weekMain == null) {
			return new R(CommonConstants.FAIL, "根据 weekId 查询不到周报信息，请确认", false);
		}
		//计算时间段
		LocalDate startWeekDate = weekMain.getStartWeekDate();
		LocalDate endWeekDate = weekMain.getEndWeekDate();
		LocalDateTime startTime = startWeekDate.atTime(0, 0, 0, 0);
		LocalDateTime endTime = endWeekDate.atTime(23, 59, 59);

		List<HomeworkDaysPlayingModeVO> HomeworkDaysPlayingModes = weekDataMemberMapper
				.getHomeworkDaysPlayingModeHours(studentId, startTime, endTime, dateTime);

		for (int i = 0; i < 24; i++) {

			Map<String, HomeworkDaysPlayingModeVO> resMap = new HashMap<>(2);
			//初始化时间
			HomeworkDaysPlayingModeVO homeworkDaysPlayingMode1 = new HomeworkDaysPlayingModeVO();
			HomeworkDaysPlayingModeVO homeworkDaysPlayingMode2 = new HomeworkDaysPlayingModeVO();
			homeworkDaysPlayingMode1.setPlayingMode("1");
			homeworkDaysPlayingMode2.setPlayingMode("2");
			homeworkDaysPlayingMode1.setHour(String.valueOf(i));
			homeworkDaysPlayingMode2.setHour(String.valueOf(i));
			homeworkDaysPlayingMode1.setPlayTimes(0d);
			homeworkDaysPlayingMode2.setPlayTimes(0d);
			resMap.put("playingMode1", homeworkDaysPlayingMode1);
			resMap.put("playingMode2", homeworkDaysPlayingMode2);

			//查询是否有 {i} 点的数据
			for (HomeworkDaysPlayingModeVO homeworkDaysPlayingMode : HomeworkDaysPlayingModes) {
				if (StringUtils.isNotBlank(homeworkDaysPlayingMode.getHour())
						&& i == Integer.parseInt(homeworkDaysPlayingMode.getHour())) {
					if ("1".equals(homeworkDaysPlayingMode.getPlayingMode())) {
						resMap.put("playingMode1", homeworkDaysPlayingMode);
						continue;
					}
					if ("2".equals(homeworkDaysPlayingMode.getPlayingMode())) {
						resMap.put("playingMode2", homeworkDaysPlayingMode);
					}
				}
			}

			resList.add(resMap);
		}

		return new R(resList);
	}

}
